﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;

namespace GiMess
{
    public partial class MainForm : Form
    {
        #region SignIn Controls

        private Panel   loginPanel;
        private PictureBox logoBox;
        private TextBox userNameTextBox;
        private TextBox userPasswordTextBox;
        private Label   userNameLabel;
        private Label   userPasswordLabel;
        private Button  signInButton;
        private Button  createAccButton;

        #endregion

        private GiNetClient giClient;

        private Color textBgColor = Color.FromArgb(177, 180, 0);
        private Color offlineColor = Color.FromArgb(255, 192, 128);
        private Color onlineColor = Color.FromArgb(192, 255, 192);

        public MainForm()
        {
            InitializeComponent();
            InitLoginScreen();
            giClient = new GiNetClient();
        }

        private void InitLoginScreen()
        {
            Size comSize = new Size(160, 20);
            loginPanel = new Panel();
            
            //loginPanel.Dock = DockStyle.Fill;
            loginPanel.Size     = new Size(this.Width, this.Height);
            loginPanel.Location = new Point(0, 0);
            loginPanel.Anchor   = (byte)AnchorStyles.Left + (byte)AnchorStyles.Right + (byte)AnchorStyles.Top + AnchorStyles.Bottom;
            loginPanel.BackColor = Color.FromArgb(77, 133, 62); 
            loginPanel.Name     = "loginPanel";

            logoBox = new PictureBox();
            logoBox.Size = new Size(90, 100);
            logoBox.Image = GiMess.Properties.Resources.matrix_icon as Image;
            logoBox.Location = new Point(90, 15);
            logoBox.SizeMode = PictureBoxSizeMode.Zoom;

            userNameTextBox = new TextBox();
            userNameTextBox.Size     = comSize;
            userNameTextBox.Location = new Point(50, 150);
            userNameTextBox.Name     = "userNameTextBox";
            userNameTextBox.BackColor = textBgColor;
            userNameTextBox.BorderStyle = BorderStyle.FixedSingle;

            userPasswordTextBox = new TextBox();
            userPasswordTextBox.Size     = comSize;
            userPasswordTextBox.Location = new Point(50, 200);
            userPasswordTextBox.Name     = "userPasswordTextBox";
            userPasswordTextBox.PasswordChar = '●';
            userPasswordTextBox.BackColor = textBgColor;
            userPasswordTextBox.BorderStyle = BorderStyle.FixedSingle;

            userNameLabel = new Label();
            userNameLabel.Size      = comSize;
            userNameLabel.Location  = new Point(50, 130);
            userNameLabel.Text      = "Username:";
            userNameLabel.Name      = "userNameLabel";

            userPasswordLabel = new Label();
            userPasswordLabel.Size     = comSize;
            userPasswordLabel.Location = new Point(50, 180);
            userPasswordLabel.Text     = "Password:";
            userPasswordLabel.Name     = "userPasswordLabel";


            signInButton = new Button();
            signInButton.Size      = new Size(70, 27);
            signInButton.Location  = new Point(95, 260);
            signInButton.Text      = "Sign In";
            signInButton.Name      = "signInButton";
            signInButton.Click    += new EventHandler(signInButton_Click);

            createAccButton = new Button();
            createAccButton.Size     = new Size(100, 27);
            createAccButton.Location = new Point(80, 290);
            createAccButton.Text     = "New account";
            createAccButton.Name     = "createAccButton";
            createAccButton.Click   += new EventHandler(createAccButton_Click);

            userNameTextBox.Text = "dburner";
            userPasswordTextBox.Text = "gimes";

            loginPanel.Controls.Add(logoBox);
            loginPanel.Controls.Add(userNameLabel);
            loginPanel.Controls.Add(userPasswordLabel);
            loginPanel.Controls.Add(userNameTextBox);
            loginPanel.Controls.Add(userPasswordTextBox);
            loginPanel.Controls.Add(signInButton);
            loginPanel.Controls.Add(createAccButton);

            this.Controls.Add(loginPanel);
            this.Controls["loginPanel"].BringToFront();

            this.AcceptButton = signInButton;
        }

        public void HideLoginScreen()
        {
            loginPanel.Invoke(new MethodInvoker(delegate()
                {
                    this.AcceptButton  = null;
                    loginPanel.Visible = false;
                }));
        }

        public void SetOwnAvatar(Image image)
        {
            avatarButton.BackgroundImage = image;
        }

        #region List related functions
        
        #region Public  List invoking functions

        public void ListInvokeAddAvatar(string key, Image image)
        {
            //avatarList.Images.RemoveByKey(key);
            avatarList.Images.Add(key, image);
        }

        public void ListInvokeAddListGroup(string group)
        {
            friendsView.Invoke(new MethodInvoker(() => { if (ListGetGroup(group) == null) ListCreateGroup(group); }));
        }

        public void ListInvokeInvalidate()
        {
            friendsView.Invoke(new MethodInvoker(() => ListInvalidate()));
        }

        public void ListInvokeAddListUser(UserFriend friend)
        {
            friendsView.Invoke(new MethodInvoker(delegate() { ListAddListUser(friend); }));
        }

        public void ListInvokeSetUserOnline(string username, bool online)
        {
            friendsView.Invoke(new MethodInvoker(delegate() { ListSetUserOnline(username, online); }));
        }

        public void ListInvokeSetUserStatus(string username, string status)
        {
            friendsView.Invoke(new MethodInvoker(() => ListSetUserStatus(username, status)));
        }

        public void ListInvokeSetUserAvatar(string username, string avatarHash)
        {
            friendsView.Invoke(new MethodInvoker(() => ListSetUserAvatar(username, avatarHash)));
        }

        #endregion

        #region Private List invoked  functions

        private void ListInvalidate()
        {
            foreach (TreeNode group in friendsView.Nodes)
                foreach (TreeNode user in group.Nodes)
                {
                    UserFriend tag = user.Tag as UserFriend;
                    if (tag.Avatar != "")
                    {
                        if (avatarList.Images.ContainsKey(tag.Username))
                        {
                            user.ImageIndex = -1;
                            user.SelectedImageIndex = -1;
                            user.ImageKey = tag.Username;
                            user.SelectedImageKey = tag.Username;
                        }
                    }
                }
            friendsView.Invalidate();
        }

        private void ListSetUserAvatar(string username, string avatarHash)
        {
            for (int i = 0; i<friendsView.Nodes.Count; i++)
                for (int j = 0; j < friendsView.Nodes[i].Nodes.Count; j++)
                    if (friendsView.Nodes[i].Nodes[j].Name == username)
                    {
                        UserFriend node = (UserFriend)friendsView.Nodes[i].Nodes[j].Tag;
                        node.Avatar = avatarHash;
                        avatarList.Images.RemoveByKey(node.Username);
                        AvatarDownloader.AddToQueue(node.Username, avatarHash);
                        return;
                    }                
        }

        private void ListSetUserOnline(string username, bool online)
        {
            for (int i = 0; i < friendsView.Nodes.Count; i++)
            {
                if (friendsView.Nodes[i].Nodes[username] == null) continue;
                if (online)
                    friendsView.Nodes[i].Nodes[username].BackColor = onlineColor;
                else
                    friendsView.Nodes[i].Nodes[username].BackColor = offlineColor;
            }
        }

        private void ListSetUserStatus(string username, string status)
        {
            for (int i = 0; i < friendsView.Nodes.Count; i++)
                for (int j = 0; j < friendsView.Nodes[i].Nodes.Count; j++)
                    if (friendsView.Nodes[i].Nodes[j].Name == username)
                    {
                        UserFriend node = (UserFriend)friendsView.Nodes[i].Nodes[j].Tag;
                        node.Status = status;
                        friendsView.Nodes[i].Nodes[j].Text = node.FirstName + " " + node.LastName + " - " + status;
                        return;
                    }
        }
        
        private void ListAddListUser(UserFriend friend)
        {
            TreeNode groupNode;
            TreeNode newNode;
            groupNode = ListGetGroup(friend.Group);
            if (groupNode == null)
            {
                groupNode = ListCreateGroup(friend.Group);
                groupNode.BackColor = Color.FromArgb(77, 133, 62);
                groupNode.ImageIndex = 0;
                groupNode.SelectedImageIndex = 0;
                groupNode.ContextMenuStrip = groupMenuStrip;
                groupNode.Tag = null; //in tag pun null daca e grup
            }

            if (friend.Status != "") 
                newNode = groupNode.Nodes.Insert(groupNode.Nodes.Count, friend.FirstName + " " + friend.LastName + " - " + friend.Status);
            else
                newNode = groupNode.Nodes.Insert(groupNode.Nodes.Count, friend.FirstName + " " + friend.LastName);
            newNode.Name = friend.Username; //nefolositor???
            newNode.Tag = friend;
            newNode.ContextMenuStrip = contactMenuStrip;

            if (friend.Online)
                newNode.BackColor = onlineColor;
            else
                newNode.BackColor = offlineColor;
                //newNode.NodeFont = new Font(DefaultFont, FontStyle.Bold);

            if (friend.Avatar != "")
            {
                //newNode.ImageKey = friend.Username;//AvatarDownloader.Counter;
                //newNode.SelectedImageKey = friend.Username;//AvatarDownloader.Counter++;
                newNode.ImageIndex = 1;
                newNode.SelectedImageIndex = 1;
                AvatarDownloader.AddToQueue(friend.Username, friend.Avatar);
            }
            else
            {
                newNode.ImageIndex = 1;
                newNode.SelectedImageIndex = 1;
            }

            friendsView.Sort();
            friendsView.ExpandAll();

        }
        
        private TreeNode ListCreateGroup(string group)
        {
            return friendsView.Nodes.Insert(friendsView.Nodes.Count, group);
        }

        private TreeNode ListGetGroup(string group)
        {
            TreeNode node;

            for(int i = 0; i<friendsView.Nodes.Count; i++)
            {
                node = friendsView.Nodes[i];
                if (node.Text == group) return node;
            }
            return null;
        }

        #endregion

        #endregion

        #region Form related functions

        private void friendsView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node.Tag != null && e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                UserFriend tag = (UserFriend)e.Node.Tag;
                FormsManager.OpenIMForm(tag.FirstName + " " + tag.LastName, e.Node.Name);
            }
        }

        private void signInButton_Click(object sender, EventArgs e)
        {
            giClient.Disconnect();
            AuthInfo.UserName = userNameTextBox.Text;
            giClient.SignIn(userNameTextBox.Text, userPasswordTextBox.Text);
        }

        private void createAccButton_Click(object sender, EventArgs e)
        {
            NewAccForm newForm = new NewAccForm();
            newForm.Show();
            //newForm.BringToFront();
        }

        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            giClient.Disconnect();
            Application.Exit();
        }

        private void signOutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //var rez = MessageBox.Show("Are you sure you want to sign out?", "GiMess SignOut", MessageBoxButtons.YesNo);
            //if (rez == System.Windows.Forms.DialogResult.No) return;

            giClient.SignOut();
            friendsView.Nodes.Clear();
            while (avatarList.Images.Count > 2)
                avatarList.Images.RemoveAt(avatarList.Images.Count - 1);
            AuthInfo.Clear();
            FormsManager.Clear();
            loginPanel.Visible = true;
        }

        private void avatarButton_Click(object sender, EventArgs e)
        {
            DialogResult result;
            result = openFileDialog.ShowDialog();
            
            if (result != System.Windows.Forms.DialogResult.OK) return;

            AvatarUploader.SetAvatar(openFileDialog.FileName);
        }

        private void statusBox_Validated(object sender, EventArgs e)
        {
            if (AuthInfo.Status != statusBox.Text)
            {
                giClient.UpdateStatusText(statusBox.Text);
                AuthInfo.Status = statusBox.Text;
            }

        }

        #endregion

        #region contactMenuStrip

        private void friendsView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                friendsView.SelectedNode = e.Node;
            }
        }

        private void sendAMessageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode node = friendsView.SelectedNode;
            if (node.Tag != null)
            {
                UserFriend tag = (UserFriend)node.Tag;
                FormsManager.OpenIMForm(tag.FirstName + " " + tag.LastName, node.Name);
            }
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode node = friendsView.SelectedNode;
            UserFriend tag = (UserFriend)node.Tag;

            node.Remove();
            giClient.ContactDelete(tag.Username);
        }

        private void moveToGroupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MoveForm.Exists) return;

            TreeNode node = friendsView.SelectedNode;
            UserFriend tag = (UserFriend)node.Tag;
            string groupName;

            var form = new MoveForm(GetGroups());
            form.Show();

            groupName = form.GetResult();

            form.Close();
            form.Dispose();

            if (groupName == "") return;

            TreeNode newGroup = ListGetGroup(groupName);
            TreeNode oldGroup = node.Parent;

            oldGroup.Nodes.Remove(node);
            newGroup.Nodes.Add(node);
            friendsView.Sort();

            giClient.ContactMove(tag.Username, groupName);
        }

        #endregion

        #region groupMenuStrip

        private string[] GetGroups()
        {
            string[] ret = new string[friendsView.Nodes.Count];

            TreeNode node;

            for (int i = 0; i < friendsView.Nodes.Count; i++)
            {
                node = friendsView.Nodes[i];
                ret[i] = node.Text;
            }

            return ret;
        }

        private void sendAMessageToGroupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (TextInputForm.Exists) return;

            string message;
            var form = new TextInputForm(false);

            form.Show();
            message = form.GetResult();

            if (message == "") return;

            foreach (TreeNode node in friendsView.SelectedNode.Nodes)
            {
                UserFriend tag = (UserFriend)node.Tag;
                giClient.SendIM(tag.Username, message, "");
            }
        }

        private void createANewGroupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (TextInputForm.Exists) return;

            string groupName;

            var form = new TextInputForm();

            form.Show();
            groupName = form.GetResult();
            form.Close();
            form.Dispose();
            if (groupName == "") return;
            giClient.GroupCreate(groupName);
            ListCreateGroup(groupName);
        }

        private void renameGroupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (TextInputForm.Exists) return;

            string newGroup;

            var form = new TextInputForm(true);

            form.Show();

            newGroup = form.GetResult();

            form.Close();
            form.Dispose();

            if (newGroup == "") return;

            giClient.GroupRename(friendsView.SelectedNode.Text, newGroup);

            friendsView.SelectedNode.Text = newGroup;
        }

        #endregion

        private void addButton_Click(object sender, EventArgs e)
        {
            var form = new AddForm(GetGroups());

            form.Show();
        }
    }
}
